import datetime

from ctaBase import *
from ctaTemplate import *
from indicators import Indicators
from utils import MinKLineGenerator

class My_RSI_V2(CtaTemplate):
    """RSI指标策略v2版本--多周期
    """
    auther = '尘心|wx:17630013170'
    className = 'My_RSI_V2'

    def __init__(self):
        super().__init__()

      # 参数映射表
        self.paramMap = {
            'exchange': '交易所',
            'vtSymbol': '合约代码',
            # 'tradetype': '交易方向', #B 买 S 卖
            'order_volume': '下单手数',
            'kline_style_x': '周期参数x', #周期参数x
            'kline_style_y': '周期参数y', #周期参数y
          }

        # 变量映射表
        self.varMap = {
            'trading': '交易中',
            'pos': '持仓',
        }

         # RSI参数及区间
        self.R = 6
        # self.S = 12
        # self.I = 24
        self.rup = 80
        self.rdm = 20

        # 定义k线周期-默认值
        self.kline_style_x = 'M1'
        self.kline_style_y = 'M5'

        self.widgetClass = KLWidget
        self.widget: KLWidget = None
        self.indicators: Indicators = None 
        self.mul:Dict[str,MinKLineGenerator] = {}
         # 策略参数
        self.exchange = ""
        self.vtSymbol = ""
        # self.tradetype = 'B' #交易方向
        self.order_volume = 1  # 下单手数
        self.kline_style = "M1" # K 线类型, 具体看 core.pyi 中的 KLineStyle 定义
        self.pay_up = 0 # 超价, 买 + 卖 -

     

        # 参数变量
        self.c_rsi_x = 0  # m1 当前tick   Rsi值 
        self.p_rsi_y = 0     # m1 上一个tick Rsi值 

        self.c_rsi_y = 0  # m5 当前tick   Rsi值 
        self.p_rsi_y = 0  # m5 上一个tick Rsi值 
      
        self.trading = False

       

    def onTick(self, tick: TickData):
        """收到行情TICK推送"""
        super().onTick(tick)

        # 过滤涨跌停和集合竟价
        if tick.lastPrice or tick.askPrice1 or tick.bidPrice1:
            self.mul[self.kline_style_x].tick_to_kline(tick)
            self.mul[self.kline_style_y].tick_to_kline(tick)

    def onInit(self):
        """程序初始化""" 
        super().onInit()

     
    def onStart(self):
        """策略启动""" 

        #获取k线数据
        self.mul[self.kline_style_x] = MinKLineGenerator(
            real_time_callback=self.real_time_callback,
            callback=self.callback,
            exchange=self.exchange,
            instrument=self.vtSymbol,
            style=self.kline_style_x
        )

        self.mul[self.kline_style_y] = MinKLineGenerator(
            real_time_callback=self.real_time_callback_y,
            callback=self.callback_y,
            exchange=self.exchange,
            instrument=self.vtSymbol,
            style=self.kline_style_y
        )

        # 获取持仓数据 Todo
        position = self.get_position(instrument=self.vtSymbol)
        self.output('合约总持仓:',position.position,'合约净持仓:',position.net_position,'总持仓可平仓数量:',position.long.position_close)

        super().onStart()

    """
        =====M1周期业务逻辑=====
    """
    def real_time_callback(self, kline: KLineData) -> None:
        """使用收到的实时推送 K 线来计算指标并更新线图"""
        # self.calc_indicator()
        rsi_val = self.mul[self.kline_style_x].producer.rsi(self.R)
        self.output('real_time_callback',rsi_val)
    
    def callback(self, kline: KLineData) -> None:
        """接受 K 线回调"""    
        self.calc_indicator(kline)
        self.calc_signal(kline)

        self.exec_signal()
        self.putEvent()

    def calc_indicator(self,kline: KLineData) -> None:
        """计算指标数据"""
        c_x_arr = self.indicators.rsi(self.R,array=True)
        # self.output(self.kline_style_x +'分钟rsi参数值:', c_x_arr[-1])

        self.c_rsi_x, self.p_rsi_x = round(c_x_arr[-1],2), round(c_x_arr[-2],2)
        
 
    def calc_signal(self, kline: KLineData) -> None:
        """计算交易信号"""
        # hour = kline.datetime.hour
        # minute = kline.datetime.minute
        # 定义尾盘，尾盘不交易并且空仓
        # self.end_of_day = hour == 14 and minute >= 40
        # 判断是否要进行交易
        self.buy_signal_x = (self.c_rsi_x > self.rdm) & (self.p_rsi_x <= self.rdm)
        self.short_signal_x = (self.c_rsi_x < self.rup) & (self.p_rsi_x >= self.rup)
        # 交易价格
        self.long_price = kline.close  #做多操作时的买入价格
        self.short_price = kline.close #做空操作时的卖出价格
        if self.buy_signal_x or self.short_signal_x: 
            # self.output(kline.__dict__)
            self.output('M1_RSI交易信号：','buy:',self.buy_signal_x,'short:',self.short_signal_x,'rsi值:',self.c_rsi_x,'上一分钟的值:',self.p_rsi_x,'当前价格:',kline.close,'交易时间',kline.datetime)

    def exec_signal(self) -> None:
        """简易交易信号执行"""
        position = self.get_position(self.vtSymbol)

        # 挂单未成交
        if self.orderID is not None:
            self.cancelOrder(self.orderID)

        self.signal = 0

        if position.net_position == 0:  #: 当前无仓位
            # 买开
            if self.buy_signal_x:
                self.signal = self.long_price

                if self.trading is False:
                    return

                self.orderID = self.buy(
                    price=(price := self.long_price + self.pay_up),
                    volume=self.order_volume
                )
                self.output(f'买入开仓信号价格: {price}')

        elif position.net_position > 0 and self.buy_signal_x:  #: 持有多头仓位
            self.signal = self.long_price

            if self.trading is False:
                return

            self.orderID = self.buy(
                price=(price := self.long_price + self.pay_up),
                volume=self.order_volume
            )
            self.output(f'买入开仓信号价格: {price}')

        # elif position.net_position < 0 and self.buy_signal:  #: 持有空头仓位
        #     self.signal = self.long_price

        #     if self.trading is False:
        #         return

        #     self.orderID = self.auto_close_position(
        #         price=(price := self.long_price + self.pay_up),
        #         volume=abs(position.net_position),
        #         symbol=self.vtSymbol,
        #         exchange=self.exchange,
        #         order_direction="buy"
        #     )
        #     self.output(f'买入平仓信号价格: {price}')
    
    
    """
        =====M5周期业务逻辑=====
    """

    def real_time_callback_y(self, kline: KLineData) -> None:
        """使用收到的实时推送 K 线来计算指标并更新线图"""
        # self.calc_indicator()


    def callback_y(self, kline: KLineData) -> None:
        """接受 K 线回调"""    
        # self.output('获取'+self.kline_style_y +'k线数据收盘价：',kline.close,kline.datetime)
        self.calc_indicator_y()

        self.calc_signal_y(kline)

        self.exec_signal_y()
        self.putEvent()


    def calc_indicator_y(self) -> None:
        """计算指标数据"""
        c_y_arr = self.indicators.rsi(self.R,array=True)
        # self.output(self.kline_style_y +'分钟rsi参数值:', c_y_arr[-1])
        self.c_rsi_y, self.p_rsi_y = round(c_y_arr[-1],2), round(c_y_arr[-2],2)
 
    def calc_signal_y(self, kline: KLineData) -> None:
        """计算交易信号"""
        # hour = kline.datetime.hour
        # minute = kline.datetime.minute
        # 定义尾盘，尾盘不交易并且空仓
        # self.end_of_day = hour == 14 and minute >= 40
        # 判断是否要进行交易
        self.buy_signal_y = (self.c_rsi_y > self.rdm) & (self.p_rsi_y <= self.rdm)
        self.short_signal_y = (self.c_rsi_y < self.rup) & (self.p_rsi_y >= self.rup)
        # 交易价格
        self.long_price = kline.close  #做多操作时的买入价格
        self.short_price = kline.close #做空操作时的卖出价格
        if self.buy_signal_y or self.short_signal_y: 
            self.output('M5_RSI交易信号：','buy:',self.buy_signal_y,'short:',self.short_signal_y,'rsi值:',self.c_rsi_y,'上一分钟的值:',self.p_rsi_y,'当前价格:',kline.close,'交易时间',kline.datetime)

    def exec_signal_y(self) -> None:
        """简易交易信号执行"""
        position = self.get_position(self.vtSymbol)

        # 挂单未成交
        if self.orderID is not None:
            self.cancelOrder(self.orderID)

        self.signal = 0

        if position.net_position == 0:  #: 当前无仓位
            pass
            # 买开，卖开
            # if self.short_signal_y:
            #     self.signal = abs(self.short_price)

            #     if self.trading is False:
            #         return

            #     self.orderID = self.short(
            #         price=(price := self.short_price - self.pay_up),
            #         volume=self.order_volume
            #     )
            #     self.output(f'卖出开仓信号价格: {price}')

            # elif self.buy_signal_y:
            #     self.signal = self.long_price

            #     if self.trading is False:
            #         return

            #     self.orderID = self.buy(
            #         price=(price := self.long_price + self.pay_up),
            #         volume=self.order_volume
            #     )
            #     self.output(f'买入开仓信号价格: {price}')

        elif position.net_position > 0 and self.short_signal_y:  #: 持有多头仓位
            self.signal = -self.short_price

            if self.trading is False:
                return

            self.orderID = self.auto_close_position(
                price=(price := self.short_price - self.pay_up),
                volume=position.net_position,
                symbol=self.vtSymbol,
                exchange=self.exchange,
                order_direction="sell"
            )
            self.output(f'卖出平仓信号价格: {price}')

        # elif position.net_position < 0 and self.buy_signal_y:  #: 持有空头仓位
        #     self.signal = self.long_price

        #     if self.trading is False:
        #         return

        #     self.orderID = self.auto_close_position(
        #         price=(price := self.long_price + self.pay_up),
        #         volume=abs(position.net_position),
        #         symbol=self.vtSymbol,
        #         exchange=self.exchange,
        #         order_direction="buy"
        #     )
        #     self.output(f'买入平仓信号价格: {price}')
    
    
    def onTrade(self, trade, log=True):
        """成交回调"""
        super().onTrade(trade, log)
        self.get_position(instrument=self.vtSymbol)

    def onStop(self):
        if self.mul[self.kline_style_x]:
            self.mul[self.kline_style_x].stop_push_scheduler()
        elif self.mul[self.kline_style_y]:
            self.mul[self.kline_style_y].stop_push_scheduler()
        super().onStop()